﻿using LxBasic;

namespace LxCore
{
    public class WallDistance : ZoneHead
    {
        protected ParameterBase<double> MinWallDistanceLimit;
        public double[] InnDis;
        //public double[] BouDis;
        public bool[] IsCellAdjWall;//标识，对于内部cell标识是否临近wall，对于边界标识是否是wall
        protected WallBoundTypes[] BoundTypes;
        protected bool isInitialized { get; set; } = false;
        public override bool IsInitialized => isInitialized;
        public override void CheckCreate(FvZone zone)
        {
            base.CheckCreate(zone);
            if (BoundTypes == null || BoundTypes.Length != zone.Bounds.Count)
            {
                BoundTypes = new WallBoundTypes[zone.Bounds.Count];
                isInitialized = false;
            }
            CheckCreator.ArrayStrict(ref InnDis, zone.Inner.CellIdx.GetCount());
            //CheckCreator.ArrayStrict(ref BouDis, zone.Inner.CellIdx.GetCount());
            CheckCreator.ArrayStrict(ref IsCellAdjWall, InnCells.Length);
        }
        public void SetZone(ParameterBase<double> minWallDisLimit)
        {
            this.MinWallDistanceLimit = minWallDisLimit;
        }
        private void setBound(int boundIndex, WallBoundTypes type)
        {
            if (BoundTypes[boundIndex] != type)
            {
                BoundTypes[boundIndex] = type;
                isInitialized = false;
            }
        }

        public void SetBound_Wall(FvBound bound)
        {
            setBound(bound.ID, WallBoundTypes.Wall);
        }
        public void SetBound_Free(FvBound bound)
        {
            setBound(bound.ID, WallBoundTypes.Free);
        }
        public void SetBound_Inner(FvBound bound)
        {
            setBound(bound.ID, WallBoundTypes.Inner);
        }
        public PossionEquation MakePDECalulator()
        {
            MultiThreads.RunParallelTask((threadInfo) =>
            {
                (int i1, int endp1) = Zone.Inner.CellIdx.Split(threadInfo);
                Array.Clear(IsCellAdjWall, i1, endp1 - i1);
            });
            PossionEquation walldis = new PossionEquation();
            walldis.CheckCreate(Zone);
            walldis.SetZone_CommonTerm(ConstField.Double1, ConstField.Double0, ConstField.Double0, ConstField.Double1);
            walldis.SetZone_DiffTerm(ConstField.Double1);
            for (int i1 = 0; i1 < BoundTypes.Length; i1++)
            {
                switch (BoundTypes[i1])
                {
                    case WallBoundTypes.Wall:
                        walldis.SetBound_FixValueWall(ConstField.Double0, Zone.Bounds[i1]);
                        break;
                    case WallBoundTypes.Free:
                        walldis.SetBound_Symmetry(Zone.Bounds[i1]);
                        break;
                    case WallBoundTypes.Inner:
                        walldis.SetBound_CoupledWall(ConstField.Double0, ConstField.Double0, Zone.Bounds[i1]);
                        break;
                }
            }
            return walldis;
        }
        public void CalDistanceFromPDE(EquationBase PDE, ThreadInfo threadInfo)
        {
            {
                //double mindis = LxResHelper.GetZoneSet(Zone).Material.ReferenceValue.MinWallDistanceLimit;
                double MinWallDistanceLimit = this.MinWallDistanceLimit.GetPara();
                double[] PDEx = PDE.InnX;
                Vector3d[] gradx = PDE.Grad;
                (int i1, int endp1) = Zone.Inner.CellIdx.Split(threadInfo);
                for (; i1 < endp1; i1++)
                {
                    double square = gradx[i1].LengthSquared();
                    double d = Math.Sqrt(square + 2 * PDEx[i1]) - Math.Sqrt(square);
                    InnDis[i1] = Math.Max(d, MinWallDistanceLimit);
                }
            }
            {
                for (int i1 = 0; i1 < BoundTypes.Length; i1++)
                {
                    (int i3, int endp1) = Zone.Bounds[i1].CellIdx.Split(threadInfo);
                    if (BoundTypes[i1] == WallBoundTypes.Wall)
                    {
                        //Array.Fill(IsCellAdjWall, true, i3, endp1 - i3);
                        for (; i3 < endp1; i3++)
                        {
                            IsCellAdjWall[BouFaces[i3].OSideCell] = true;
                        }
                    }
                }
            }
            if (threadInfo.CurrentThreadID == 0) isInitialized = true;
        }
        protected enum WallBoundTypes : byte
        {
            Wall, Free, Inner,
        }
    }
}
